home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / Book Chapters / 10 - Networking / NovelNetwar / appletalking.c < prev    next >
C/C++ Source or Header  |  1995-05-12  |  41KB  |  1,627 lines

  1. #include "NovelNetwar.h"
  2.  
  3.  
  4. //    a few useful definitions....
  5.  
  6. #define NBPNETTYPE                "\pNetShootout"
  7.  
  8. #define MAXNUMNBPNAMES            10L
  9. #define NBPNAMESIZE                104L
  10. #define MAXATPPACKETSIZE        578
  11. #define MYGAMEDDPSOCKETNUMBER    64
  12. #define DDPBROADCASTNODE        255
  13.  
  14. #define MYDDPPACKETTYPE            0xAA
  15.  
  16.  
  17. //    I'm not sure why this one isn't in the Universal Header files, but it's not
  18.  
  19. #define toRHA                    1
  20.  
  21.  
  22. //    there must be a better way to do this, but....
  23.  
  24. #define NUMSTATICTEXTITEMS        10
  25.  
  26.  
  27.  
  28.  
  29. //    we'll be sneaky and prepend the saved value of A5 to our ATP parameter blocks so we can get it back and later access application globals!
  30.  
  31. struct ATPParamBlockPlusA5 
  32. {
  33.     unsigned long    A5;
  34.     ATPParamBlock    theATPParamBlock;
  35. };
  36. typedef struct ATPParamBlockPlusA5 ATPParamBlockPlusA5;
  37.  
  38.  
  39.  
  40.  
  41.  
  42.  
  43.  
  44. //    en enumerated type to keep track of our status
  45.  
  46. enum { UNKNOWN, INITIALIZING, WAITING, PLAYING, CLOSING };
  47.  
  48.  
  49. //    private variables
  50.  
  51. static int                        appletalkingStatus;    //    status of our AppleTalk efforts
  52. static short                    myNetNum,myNodeNum;    //    our node and netowrk number
  53. static UInt8                    myATPSocketNum,myDDPSocketNum;    //    our socket numbers
  54. static Str32                    myNBPName,myNBPNetType = NBPNETTYPE;    //    our network name and our NBP typename
  55. static char                        atpSocketOpened,nbpRegistered,doAsynchATP,ddpSocketOpened,ddpWriteFirstTime;    //    lots of flags to track what we've done
  56. static Ptr                        myNamesTableEntry,myATPAsynchReceiveBuffer,myATPAsynchReplyBuffer;    //    our buffers
  57. static ATPParamBlockPlusA5        myAsynchReceiveATPPB,myAsynchReplyATPPB;    //    our ATP parameter blocks
  58. static BDSType                    asynchATPReplyBDS;    // our ATP BDS structure
  59. static AddrBlock                asynchATPReplyAddrBlock;    //    our ATP reply address block
  60. static short                    asynchATPReplyTransID;    // the transaction ID for the ATP reply
  61. static DDPDataPacket            myDDPReadBuffer,myDDPWriteBuffer;    //    more buffers
  62. static MPPParamBlock            theDDPWriteMPPPB;    //    another buffer
  63. static char                        myDDPwds[14],myDDPheader[18];    // our DDP write data structure and DDP header storage
  64. static AddrBlock                myDDPBroadcastAddress;    // the DDP broadcast address block
  65.  
  66.  
  67.  
  68.  
  69. static asm void ATPReceiveCompletionRoutineASM(void);
  70. static void ATPReceiveCompletionC(unsigned long A5,ATPParamBlock * theRequestATPPB);
  71. static asm void ATPReplyCompletionRoutineASM(void);
  72. static void ATPReplyCompletionC(unsigned long A5,ATPParamBlock * theReplyATPPB);
  73. static asm void initMyDDPSocketListener(void);
  74. static asm void myDDPSocketListener(void);
  75. static asm void myDDPSocketListenerASMCode(void);
  76. static void processDDPPacket(void);
  77.  
  78.  
  79.  
  80.  
  81. //    Initialize state variables, etc.
  82.  
  83. void appletalkingInit(void)
  84. {
  85.     atpSocketOpened = false;
  86.     ddpSocketOpened = false;
  87.     nbpRegistered = false;
  88.     doAsynchATP = false;
  89.     ddpWriteFirstTime = true;
  90.     
  91.     myNamesTableEntry = nil;
  92.     myATPAsynchReceiveBuffer = nil;
  93.     myATPAsynchReplyBuffer = nil;
  94.     
  95.     myAsynchReceiveATPPB.theATPParamBlock.ATP.ioResult = 0;
  96.     myAsynchReplyATPPB.theATPParamBlock.ATP.ioResult = 0;
  97.     theDDPWriteMPPPB.DDP.ioResult = 0;
  98.         
  99.     appletalkingStatus = INITIALIZING;
  100. }
  101.  
  102.  
  103.  
  104. //    Try to allocate buffers, open AppleTalk, etc.
  105.  
  106. void appletalkingStartup(void)
  107. {
  108. OSErr                errCode;
  109. ATPParamBlock        myATPPB;
  110. MPPParamBlock        myMPPPB,myCancelMPPPB;
  111. char                tempString[256];
  112. int                    i;
  113. DialogPtr            theDPtr,tempDPtr;
  114. short                itemHit,type;
  115. Handle                theItem;
  116. Rect                tempRect;
  117. GrafPtr                oldPort;
  118. EventRecord            theEvent;
  119. Handle                theMachineName;
  120.  
  121.     //    check the global flag defined in globals.c
  122.     
  123.     if (hasAppleTalk == false || connectionMethod != APPLETALK)
  124.     {
  125.         return;
  126.     }
  127.     
  128.     
  129.     theDPtr = nil;
  130.     oldPort = nil;
  131.     
  132.     GetPort(&oldPort);
  133.     
  134.     InitCursor();
  135.     
  136.     //    check and maybe open AppleTalk
  137.     
  138.     if (IsMPPOpen() == false)
  139.     {
  140.         errCode = MPPOpen();
  141.         
  142.         if (errCode != noErr)
  143.         {
  144.             sprintf(errorMessage,"appletalkingStartup: MPPOpen() error %d, can't open the AppleTalk MPP driver!",(int) errCode);
  145.             
  146.             ErrorAlert(errorMessage);
  147.             
  148.             goto EXITPOINT;
  149.         }
  150.     }
  151.     
  152.     
  153.     //    I commented this out, but it's nice to know you can always put it back and play against yourself....
  154.     
  155. /*    
  156.     myMPPPB.SETSELF.newSelfFlag = true;
  157.     
  158.     errCode = PSetSelfSend(&myMPPPB,false);
  159.     
  160.     if (errCode != noErr)
  161.     {
  162.         sprintf(errorMessage,"appletalkingStartup: PSetSelfSend() error %d, can't turn on self-sending!",(int) errCode);
  163.         
  164.         ErrorAlert(errorMessage);
  165.         
  166.         goto EXITPOINT;
  167.     }
  168. */
  169.     
  170.     
  171.     //    find out where we are on the network
  172.     
  173.     errCode = GetNodeAddress(&myNodeNum,&myNetNum);
  174.     
  175.     if (errCode != noErr)
  176.     {
  177.         sprintf(errorMessage,"appletalkingStartup: GetNodeAddress() error %d, can't look up AppleTalk node/net address!",(int) errCode);
  178.         
  179.         ErrorAlert(errorMessage);
  180.             
  181.         goto EXITPOINT;
  182.     }
  183.     
  184.     
  185.     //    open an ATP socket
  186.     
  187.     myATPPB.ATP.atpSocket = 0;
  188.     myATPPB.ATP.addrBlock.aNet = 0;
  189.     myATPPB.ATP.addrBlock.aNode = 0;
  190.     myATPPB.ATP.addrBlock.aSocket = 0;
  191.  
  192.     errCode = POpenATPSkt(&myATPPB,false);
  193.     
  194.     if (errCode != noErr)
  195.     {
  196.         sprintf(errorMessage,"appletalkingStartup: POpenATPSkt() error %d, can't allocate an ATP socket!",(int) errCode);
  197.         
  198.         ErrorAlert(errorMessage);
  199.         
  200.         goto EXITPOINT;
  201.     }
  202.     
  203.     atpSocketOpened = true;
  204.     
  205.     myATPSocketNum = myATPPB.ATP.atpSocket;
  206.     
  207.     
  208.     
  209.     //    initialize the DDP listener socket
  210.     
  211.     initMyDDPSocketListener();
  212.     
  213.     
  214.     //    open a DDP socket and connect our listener to it
  215.     
  216.     myMPPPB.DDP.socket = MYGAMEDDPSOCKETNUMBER;
  217.     myMPPPB.DDP.u.listener = (DDPSocketListenerUPP) myDDPSocketListener;
  218.  
  219.     errCode = POpenSkt(&myMPPPB,false);
  220.     
  221.     if (errCode != noErr)
  222.     {
  223.         sprintf(errorMessage,"appletalkingStartup: POpenSkt() error %d, can't allocate a DDP socket!",(int) errCode);
  224.         
  225.         ErrorAlert(errorMessage);
  226.         
  227.         goto EXITPOINT;
  228.     }
  229.     
  230.     ddpSocketOpened = true;
  231.     
  232.     if (myMPPPB.DDP.socket != MYGAMEDDPSOCKETNUMBER)
  233.     {
  234.         sprintf(errorMessage,"appletalkingStartup: POpenSkt() opened socket #%d when asked to open #%d!",(int) myMPPPB.DDP.socket,(int) MYGAMEDDPSOCKETNUMBER);
  235.         
  236.         ErrorAlert(errorMessage);
  237.         
  238.         goto EXITPOINT;
  239.     }
  240.     
  241.     myDDPSocketNum = myMPPPB.DDP.socket;
  242.     
  243.     
  244.     
  245.     //    allocate some buffers
  246.     
  247.     myATPAsynchReceiveBuffer = NewPtr(MAXATPPACKETSIZE);
  248.     
  249.     errCode = MemError();
  250.     
  251.     if (errCode != noErr || myATPAsynchReceiveBuffer == nil)
  252.     {
  253.         sprintf(errorMessage,"appletalkingStartup: NewPtr() error %d, cannot setup asynch ATP receive buffer!",(int) errCode);
  254.         
  255.         ErrorAlert(errorMessage);
  256.         
  257.         goto EXITPOINT;
  258.     }
  259.     
  260.     
  261.     myATPAsynchReplyBuffer = NewPtr(MAXATPPACKETSIZE);
  262.     
  263.     errCode = MemError();
  264.     
  265.     if (errCode != noErr || myATPAsynchReplyBuffer == nil)
  266.     {
  267.         sprintf(errorMessage,"appletalkingStartup: NewPtr() error %d, cannot setup asynch ATP reply buffer!",(int) errCode);
  268.         
  269.         ErrorAlert(errorMessage);
  270.         
  271.         goto EXITPOINT;
  272.     }
  273.     
  274.     
  275.     // ensure that the ATP completion routine will keep posting another asynch receive
  276.     
  277.     doAsynchATP = true;
  278.     
  279.     
  280.     // get that first ATP request    
  281.  
  282.     myAsynchReceiveATPPB.A5 = SetCurrentA5();    //    save A5 for later use in the completion routine to access application globals
  283.     
  284.     myAsynchReceiveATPPB.theATPParamBlock.ATP.ioCompletion = (ATPCompletionUPP) ATPReceiveCompletionRoutineASM;
  285.     myAsynchReceiveATPPB.theATPParamBlock.ATP.atpSocket = myATPSocketNum;
  286.     myAsynchReceiveATPPB.theATPParamBlock.ATP.reqLength = MAXATPPACKETSIZE;
  287.     myAsynchReceiveATPPB.theATPParamBlock.ATP.reqPointer = myATPAsynchReceiveBuffer;
  288.     
  289.     errCode = PGetRequest(&(myAsynchReceiveATPPB.theATPParamBlock),true);
  290.     
  291.     if (errCode != noErr)
  292.     {
  293.         sprintf(errorMessage,"appletalkingStartup: PGetRequest() error %d, can't listen for asynch ATP requests!",(int) errCode);
  294.         
  295.         ErrorAlert(errorMessage);
  296.         
  297.         goto EXITPOINT;
  298.     }
  299.     
  300.     
  301.     //    get the machine name if it's set, otherwise ask the user who we are
  302.     
  303.     theMachineName = GetResource('STR ',-16413);
  304.     
  305.     if (theMachineName != nil && *theMachineName != nil && **theMachineName != 0)
  306.     {
  307.         HLock(theMachineName);
  308.         mystrncpy((char *) *theMachineName,tempString,255);
  309.         HUnlock(theMachineName);
  310.         ReleaseResource(theMachineName);
  311.     }
  312.     
  313.     else
  314.     {
  315.         sprintf(tempString,"NetShootout@%d:%d:%d",(int) myNetNum,(int) myNodeNum,(int) myATPSocketNum);
  316.     }
  317.     
  318.     
  319.     errCode = GetInput("Choose your network name:",tempString);
  320.     
  321.     if (errCode != noErr)
  322.     {
  323.         errCode = NONETNAME;
  324.         
  325.         sprintf(errorMessage,"appletalkingStartup: no network name specified!");
  326.         
  327.         ErrorAlert(errorMessage);
  328.         
  329.         goto EXITPOINT;
  330.     }
  331.     
  332.     
  333.     //    screen out wildcard characters
  334.     
  335.     for (i=0;i<strlen(tempString);i++)
  336.     {
  337.         if (tempString[i] == '*' || tempString[i] == '≈' || tempString[i] == '=')
  338.             tempString[i] = '•';
  339.     }
  340.     
  341.     mystrncpy((char *) &myNBPName,tempString,sizeof(myNBPName));
  342.     CtoPstr((char *) myNBPName);
  343.     
  344.     
  345.     //    register us with NBP
  346.     
  347.     myNamesTableEntry = NewPtr(sizeof(NamesTableEntry));
  348.     
  349.     errCode = MemError();
  350.     
  351.     if (errCode != noErr || myNamesTableEntry == nil)
  352.     {
  353.         sprintf(errorMessage,"appletalkingStartup: NewPtr() error %d, cannot register NBP name!",(int) errCode);
  354.         
  355.         ErrorAlert(errorMessage);
  356.         
  357.         goto EXITPOINT;
  358.     }
  359.     
  360.     
  361.     theDPtr = GetNewDialog(INFOCANCELDLOG,nil,(WindowPtr) -1L);
  362.     
  363.     if (theDPtr != nil)
  364.     {
  365.         SetPort(theDPtr);
  366.         
  367.         ((DialogPeek) theDPtr)->aDefItem = -1;
  368.         
  369.         GetDItem(theDPtr, 2, &type, &theItem, &tempRect);
  370.         SetIText(theItem,"\pPlease wait— registering network name....");
  371.         
  372.         CenterWindow(theDPtr);
  373.         ShowWindow(theDPtr);
  374.         
  375.         if (GetNextEvent(updateMask,&theEvent))
  376.         {
  377.             if ((DialogPtr) theEvent.message == theDPtr)
  378.             {
  379.                 DialogSelect(&theEvent,&tempDPtr,&itemHit);
  380.             }
  381.         }
  382.     }
  383.     
  384.     NBPSetNTE(myNamesTableEntry,myNBPName,myNBPNetType,"\p*",myATPSocketNum);
  385.     
  386.     myMPPPB.NBP.ioCompletion = nil;
  387.     myMPPPB.NBP.interval = 0x0F;
  388.     myMPPPB.NBP.count = 0x03;
  389.     myMPPPB.NBP.nbpPtrs.entityPtr = myNamesTableEntry;
  390.     myMPPPB.NBP.parm.verifyFlag = true;
  391.     
  392.     errCode = PRegisterName(&myMPPPB,true);
  393.     
  394.     if (errCode != noErr)
  395.     {
  396.         sprintf(errorMessage,"appletalkingStartup: PRegisterName() error %d at initial call, can't register NBP name!",(int) errCode);
  397.         
  398.         ErrorAlert(errorMessage);
  399.         
  400.         goto EXITPOINT;
  401.     }
  402.     
  403.     
  404.     //    wait for the NBP registration to complete and allow the user to cancel the operation
  405.     
  406.     do 
  407.     {
  408.         itemHit = 0;
  409.         
  410.         if (GetNextEvent(everyEvent,&theEvent) == true && IsDialogEvent(&theEvent) == true)
  411.         {
  412.             //    this calls my custom dialog command key handler to allow recognition of the escape key, etc.
  413.             
  414.             if (ProcessDialogCmdKey(theDPtr,&theEvent,&itemHit) == true)
  415.             {
  416.             
  417.             }
  418.             
  419.             
  420.             else if (DialogSelect(&theEvent,&tempDPtr,&itemHit) == true)
  421.             {
  422.                 if (tempDPtr != theDPtr)
  423.                     itemHit = 0;
  424.             }
  425.             
  426.             else
  427.             {
  428.                 itemHit = 0;
  429.             }
  430.         }
  431.         
  432.     } while (itemHit != 1 && myMPPPB.NBP.ioResult == 1);
  433.     
  434.  
  435.     //    if the user cancelled, then kill the call to NBPRegister
  436.     
  437.     if (itemHit == 1)
  438.     {
  439.         myCancelMPPPB.NBPKILL.nKillQEl = (Ptr) &myMPPPB;
  440.         
  441.         PKillNBP(&myCancelMPPPB,false);
  442.     }
  443.     
  444.     else
  445.     {
  446.         if (myMPPPB.NBP.ioResult == noErr)
  447.         {
  448.             nbpRegistered = true;
  449.         }
  450.         
  451.         else
  452.         {
  453.             sprintf(errorMessage,"appletalkingStartup: PRegisterName() error %d after asynch completion, can't register NBP name!",(int) errCode);
  454.             
  455.             ErrorAlert(errorMessage);
  456.             
  457.             goto EXITPOINT;
  458.         }
  459.     }
  460.     
  461.     
  462. EXITPOINT:
  463.  
  464.     if (theDPtr != nil)
  465.     {
  466.         DisposDialog(theDPtr);
  467.     }
  468.     
  469.     if (oldPort != nil)
  470.     {
  471.         SetPort(oldPort);
  472.     }
  473. }
  474.  
  475.  
  476.  
  477.  
  478. //    Prepare for exiting-- close sockets, deallocate buffers, etc.
  479.  
  480. void appletalkingShutdown(void)
  481. {
  482. OSErr                errCode;
  483. Ptr                    myEntityBuffer;
  484. MPPParamBlock        myMPPPB;
  485. ATPParamBlock        myATPPB;
  486. long                initialTicks;
  487.     
  488.     //    again, check the global defined in globals.c
  489.     
  490.     if (hasAppleTalk == false)
  491.     {
  492.         return;
  493.     }
  494.     
  495.     
  496.     //    keep track of our status
  497.     
  498.     appletalkingStatus = CLOSING;
  499.     
  500.     
  501.     //    unregister with NBP
  502.     
  503.     if (nbpRegistered == true)
  504.     {
  505.         myEntityBuffer = NewPtr(256L);
  506.         
  507.         errCode = MemError();
  508.         
  509.         if (errCode != noErr || myEntityBuffer == nil)
  510.         {
  511.             sprintf(errorMessage,"appletalkingShutdown: NewPtr() error %d, cannot allocate buffer for use in removing NBP name!",(int) errCode);
  512.             
  513.             ErrorAlert(errorMessage);
  514.         }
  515.         
  516.         else
  517.         {
  518.             //    remove our name from the NBP tables
  519.             
  520.             myMPPPB.NBP.nbpPtrs.entityPtr = (*((NamesTableEntry *) myNamesTableEntry)).nt.entityData;
  521.             
  522.             errCode = PRemoveName(&myMPPPB,false);
  523.             
  524.             if (errCode != noErr)
  525.             {
  526.                 sprintf(errorMessage,"appletalkingShutdown: PRemoveName() error %d, cannot remove NBP name!",(int) errCode);
  527.                 
  528.                 ErrorAlert(errorMessage);
  529.             }
  530.             
  531.             DisposePtr(myEntityBuffer);
  532.             
  533.             myEntityBuffer = nil;
  534.             
  535.             nbpRegistered = false;
  536.         }
  537.     }
  538.     
  539.     
  540.     
  541.     if (myNamesTableEntry != nil)
  542.     {
  543.         DisposePtr(myNamesTableEntry);
  544.         
  545.         myNamesTableEntry = nil;
  546.     }
  547.     
  548.     
  549.     //    killoutstanding ATP read requests
  550.     
  551.     if (myAsynchReceiveATPPB.theATPParamBlock.ATP.ioResult == 1)
  552.     {
  553.         myATPPB.KILL.aKillQEl = (Ptr) &(myAsynchReceiveATPPB.theATPParamBlock);
  554.         
  555.         errCode = PKillGetReq(&myATPPB,false);
  556.         
  557.         if (errCode != noErr)
  558.         {
  559.             sprintf(errorMessage,"appletalkingShutdown: PKillGetReq() error %d, can't kill asynch ATP GetRequest!",(int) errCode);
  560.             
  561.             ErrorAlert(errorMessage);
  562.         }
  563.     }
  564.     
  565.     if (myAsynchReplyATPPB.theATPParamBlock.ATP.ioResult == 1)
  566.     {
  567.         myATPPB.ATP.atpSocket = myATPSocketNum;
  568.         myATPPB.ATP.addrBlock.aNet = asynchATPReplyAddrBlock.aNet;
  569.         myATPPB.ATP.addrBlock.aNode = asynchATPReplyAddrBlock.aNode;
  570.         myATPPB.ATP.addrBlock.aSocket = asynchATPReplyAddrBlock.aSocket;
  571.         myATPPB.OTH2.transID = asynchATPReplyTransID;
  572.         
  573.         errCode = PRelRspCB(&myATPPB,false);
  574.         
  575.         if (errCode != noErr && errCode != cbNotFound)
  576.         {
  577.             sprintf(errorMessage,"appletalkingShutdown: PRelRspCB() error %d, can't kill asynch ATP SendResponse!",(int) errCode);
  578.             
  579.             ErrorAlert(errorMessage);
  580.         }
  581.     }
  582.     
  583.     
  584.     //    kill outstanding DDP write attempts
  585.     
  586.     if (theDDPWriteMPPPB.DDP.ioResult == 1)
  587.     {
  588.         initialTicks = TickCount();
  589.         
  590.         while (TickCount() < initialTicks + 60*60)
  591.         {
  592.         
  593.         }
  594.         
  595.         if (theDDPWriteMPPPB.DDP.ioResult == 1)
  596.         {
  597.             ErrorAlert("appletalkingShutdown: an asynch DDP write call has not completed, but the DDP socket will be closed anyway....");
  598.         }
  599.     }
  600.     
  601.     
  602.     //    dispose of buffers
  603.     
  604.     if (myATPAsynchReceiveBuffer != nil)
  605.     {
  606.         DisposePtr(myATPAsynchReceiveBuffer);
  607.         
  608.         myATPAsynchReceiveBuffer = nil;
  609.     }
  610.     
  611.     
  612.     if (myATPAsynchReplyBuffer != nil)
  613.     {
  614.         DisposePtr(myATPAsynchReplyBuffer);
  615.         
  616.         myATPAsynchReplyBuffer = nil;
  617.     }
  618.     
  619.     
  620.     //    close sockets
  621.     
  622.     if (atpSocketOpened)
  623.     {
  624.         myATPPB.ATP.atpSocket = myATPSocketNum;
  625.     
  626.         errCode = PCloseATPSkt(&myATPPB,false);
  627.         
  628.         if (errCode != noErr)
  629.         {
  630.             sprintf(errorMessage,"appletalkingShutdown: PCloseATPSkt() error %d, can't close ATP socket!",(int) errCode);
  631.             
  632.             ErrorAlert(errorMessage);
  633.         }
  634.         
  635.         atpSocketOpened = false;
  636.     }
  637.     
  638.     
  639.     if (ddpSocketOpened)
  640.     {
  641.         myMPPPB.DDP.socket = myDDPSocketNum;
  642.     
  643.         errCode = PCloseSkt(&myMPPPB,false);
  644.         
  645.         if (errCode != noErr)
  646.         {
  647.             sprintf(errorMessage,"appletalkingShutdown: PCloseSkt() error %d, can't close DDP socket!",(int) errCode);
  648.             
  649.             ErrorAlert(errorMessage);
  650.         }
  651.         
  652.         ddpSocketOpened = false;
  653.     }
  654. }
  655.  
  656.  
  657.  
  658.  
  659.  
  660. //    The nasty user-interface-intensive routine that lets players look up whoever else is on the net
  661.  
  662. OSErr appleTalkingConnectToOpponents(void)
  663. {
  664. OSErr                errCode;
  665. MPPParamBlock        myMPPPB,myCancelMPPPB;
  666. ATPParamBlock        myCancelATPPB;
  667. AddrBlock            theEntityAddress;
  668. Ptr                    nbpNamesBuffer;
  669. EntityName            theEntityName;
  670. DialogPtr            theDPtr,tempDPtr;
  671. short                itemHit,type;
  672. Handle                theItem;
  673. Rect                tempRect;
  674. GrafPtr                oldPort;
  675. WindowPtr            tempWPtr;
  676. EventRecord            theEvent;
  677. int                    i,j,numNBPScans;
  678. Str32                atpMessage;
  679. char                found;
  680. Ptr                    otherPlayerATPPBPtrs[MAXNUMPLAYERS],otherPlayerBDSPtrs[MAXNUMPLAYERS],otherPlayerRespBuffPtrs[MAXNUMPLAYERS];
  681. int                    otherPlayerResponseCount[MAXNUMPLAYERS];
  682. Str32                otherPlayerNames[MAXNUMPLAYERS];
  683. Str32                otherPlayerStatus[MAXNUMPLAYERS];
  684. short                numBDSBuffers;
  685. char                tempString[256];
  686. AddrBlock            otherPlayerAddrBlocks[MAXNUMPLAYERS];
  687. int                    numOtherPlayers;
  688.  
  689.     
  690.     //    check the global from globals.c again
  691.     
  692.     if (hasAppleTalk == false)
  693.     {
  694.         sprintf(errorMessage,"appleTalkingConnectToOpponents: AppleTalk is not available!");
  695.         
  696.         return(NOAPPLETALK);
  697.     }
  698.     
  699.     
  700.     //    initialize some variables we'll need later
  701.     
  702.     errCode = noErr;
  703.     
  704.     nbpNamesBuffer = nil;
  705.     theDPtr = nil;
  706.     oldPort = nil;
  707.     
  708.     myMPPPB.NBP.ioResult = 0;
  709.     
  710.     
  711.     for (i=0;i<MAXNUMPLAYERS;i++)
  712.     {
  713.         otherPlayerATPPBPtrs[i] = nil;
  714.         otherPlayerBDSPtrs[i] = nil;
  715.         otherPlayerRespBuffPtrs[i] = nil;
  716.     }
  717.     
  718.     
  719.     //    sanity check-- did we set up okay?
  720.     
  721.     if (nbpRegistered == false || atpSocketOpened == false)
  722.     {
  723.         goto EXITPOINT;
  724.     }
  725.     
  726.     
  727.     GetPort(&oldPort);
  728.     
  729.     
  730.     //    allocate various records we'll use in ATP pings of other players
  731.     
  732.     for (i=0;i<MAXNUMPLAYERS;i++)
  733.     {
  734.         otherPlayerATPPBPtrs[i] = NewPtr(sizeof(ATPParamBlock));
  735.         
  736.         errCode = MemError();
  737.         
  738.         if (errCode != noErr || otherPlayerATPPBPtrs[i] == nil)
  739.         {
  740.             sprintf(errorMessage,"appleTalkingConnectToOpponents: NewPtr() error %d, cannot allocate ATPParamBlock #%d for use in sending ATP Requests!",(int) errCode,(int) i);
  741.             
  742.             goto EXITPOINT;
  743.         }
  744.         
  745.         (*((ATPParamBlock *) otherPlayerATPPBPtrs[i])).ATP.ioResult = 0;
  746.         
  747.         
  748.         otherPlayerBDSPtrs[i] = NewPtr(sizeof(BDSType));
  749.         
  750.         errCode = MemError();
  751.         
  752.         if (errCode != noErr || otherPlayerBDSPtrs[i] == nil)
  753.         {
  754.             sprintf(errorMessage,"appleTalkingConnectToOpponents: NewPtr() error %d, cannot allocate BDS #%d for use in sending ATP Requests!",(int) errCode,(int) i);
  755.             
  756.             goto EXITPOINT;
  757.         }
  758.         
  759.         
  760.         otherPlayerRespBuffPtrs[i] = NewPtr(sizeof(Str32));
  761.         
  762.         errCode = MemError();
  763.         
  764.         if (errCode != noErr || otherPlayerRespBuffPtrs[i] == nil)
  765.         {
  766.             sprintf(errorMessage,"appleTalkingConnectToOpponents: NewPtr() error %d, cannot allocate response buffer #%d for use in sending ATP Requests!",(int) errCode,(int) i);
  767.             
  768.             goto EXITPOINT;
  769.         }
  770.     }
  771.     
  772.     
  773.     //    allocate storage for all the names we'll be looking up
  774.     
  775.     nbpNamesBuffer = NewPtr(MAXNUMNBPNAMES * NBPNAMESIZE);
  776.     
  777.     errCode = MemError();
  778.     
  779.     if (errCode != noErr || nbpNamesBuffer == nil)
  780.     {
  781.         sprintf(errorMessage,"appleTalkingConnectToOpponents: NewPtr() error %d, cannot allocate nbpNamesBuffer for use in looking up NBP names!",(int) errCode);
  782.         
  783.         goto EXITPOINT;
  784.     }
  785.     
  786.  
  787.     //    get the dialog box
  788.     
  789.     theDPtr = GetNewDialog(ATALKSTARTDLOG,nil,(WindowPtr) -1L);
  790.     
  791.     if (theDPtr == nil)
  792.     {
  793.         errCode = ResError();
  794.         
  795.         sprintf(errorMessage,"appleTalkingConnectToOpponents: GetNewDialog() error %d, cannot show dialog box to display looked-up network names!",(int) errCode);
  796.         
  797.         goto EXITPOINT;
  798.     }
  799.     
  800.     
  801.     SetPort(theDPtr);
  802.     
  803.     ((DialogPeek) theDPtr)->aDefItem = -1;
  804.     
  805.     GetDItem(theDPtr, 1, &type, &theItem, &tempRect);
  806.     HiliteControl((ControlHandle) theItem,255);
  807.     
  808.     //    show it....
  809.     
  810.     CenterWindow(theDPtr);
  811.     ShowWindow(theDPtr);
  812.     
  813.     //    handle that messy first update event
  814.     
  815.     if (GetNextEvent(updateMask,&theEvent))
  816.     {
  817.         if ((DialogPtr) theEvent.message == theDPtr)
  818.         {
  819.             DialogSelect(&theEvent,&tempDPtr,&itemHit);
  820.         }
  821.     }
  822.     
  823.     
  824.     //    set our state variable
  825.     
  826.     appletalkingStatus = WAITING;
  827.     
  828.     numOtherPlayers = 0;
  829.     
  830.     numNBPScans = 1;
  831.  
  832.     //    tell the user what we're up to
  833.     
  834.     GetDItem(theDPtr, 3, &type, &theItem, &tempRect);
  835.     sprintf(tempString,"Searching the network for opponents.... (attempt #%d)",(int) numNBPScans);
  836.     CtoPstr(tempString);
  837.     SetIText(theItem,(unsigned char *) tempString);
  838.     
  839.     
  840.     //    do an NBP name lookup asynchronously
  841.     
  842.     NBPSetEntity((Ptr) &theEntityName,"\p=",NBPNETTYPE,"\p*");
  843.     
  844.     myMPPPB.NBP.ioCompletion = nil;
  845.     myMPPPB.NBP.interval = 0x0F;
  846.     myMPPPB.NBP.count = 0x01;
  847.     myMPPPB.NBP.nbpPtrs.entityPtr = (Ptr) &theEntityName;
  848.     myMPPPB.NBP.parm.Lookup.retBuffPtr = nbpNamesBuffer;
  849.     myMPPPB.NBP.parm.Lookup.retBuffSize = MAXNUMNBPNAMES * NBPNAMESIZE;
  850.     myMPPPB.NBP.parm.Lookup.maxToGet = MAXNUMNBPNAMES;
  851.     
  852.     
  853.     errCode = PLookupName(&myMPPPB,true);
  854.     
  855.     if (errCode != noErr)
  856.     {
  857.         sprintf(errorMessage,"appleTalkingConnectToOpponents: PLookupName() error %d at first-time initial call, can't look up enemy player's NBP names!",(int) errCode);
  858.         
  859.         goto EXITPOINT;
  860.     }
  861.     
  862.     
  863.     //    while we're waiting for the NBP name lookup to complete, let's do some other important stuff
  864.     
  865.     do 
  866.     {
  867.         itemHit = 0;
  868.     
  869.         //    first of all, deal with keypresses, mouseclicks, etc.
  870.         
  871.         if (WaitNextEvent(everyEvent,&theEvent,0L,0L) == true)
  872.         {
  873.             if (IsDialogEvent(&theEvent) == true)
  874.             {
  875.                 if (ProcessDialogCmdKey(theDPtr,&theEvent,&itemHit) == true)
  876.                 {
  877.                 
  878.                 }
  879.                 
  880.                 else if (DialogSelect(&theEvent,&tempDPtr,&itemHit) == true && tempDPtr == theDPtr)
  881.                 {
  882.                 
  883.                 }
  884.                 
  885.                 else
  886.                 {
  887.                     itemHit = 0;
  888.                 }
  889.             }
  890.         }
  891.         
  892.         
  893.         //    did the NBP request complete?
  894.         
  895.         if (myMPPPB.NBP.ioResult != 1)
  896.         {
  897.             //    yes, so extract the names, as long as we still have room to keep track of them
  898.             
  899.             if (numOtherPlayers < MAXNUMPLAYERS)
  900.             {
  901.                 for (i=0;i < myMPPPB.NBP.parm.Lookup.numGotten;i++)
  902.                 {
  903.                     errCode = NBPExtract(nbpNamesBuffer,myMPPPB.NBP.parm.Lookup.numGotten,i+1,&theEntityName,&theEntityAddress);
  904.                     
  905.                     if (errCode != noErr)
  906.                     {
  907.                         sprintf(errorMessage,"appleTalkingConnectToOpponents: NBPExtract() error %d, can't extract an NBP name!",(int) errCode);
  908.                         
  909.                         goto EXITPOINT;
  910.                     }
  911.                     
  912.                     else
  913.                     {
  914.                         //    don't look up ourselves!
  915.                         
  916.                         if (theEntityAddress.aNet != myNetNum || theEntityAddress.aNode != myNodeNum || theEntityAddress.aSocket != myATPSocketNum)
  917.                         {
  918.                             found = false;
  919.                             
  920.                             //    do I know you?
  921.                             
  922.                             for (j=0;j<numOtherPlayers;j++)
  923.                             {
  924.                                 if (otherPlayerAddrBlocks[j].aNet == theEntityAddress.aNet && otherPlayerAddrBlocks[j].aNode == theEntityAddress.aNode && otherPlayerAddrBlocks[j].aSocket == theEntityAddress.aSocket)
  925.                                 {
  926.                                     found = true;
  927.                                     
  928.                                     break;
  929.                                 }
  930.                             }
  931.                             
  932.                             
  933.                             //    found a new one....
  934.                             
  935.                             if (found == false && numOtherPlayers < MAXNUMPLAYERS)
  936.                             {
  937.                                 otherPlayerAddrBlocks[numOtherPlayers].aNet = theEntityAddress.aNet;
  938.                                 otherPlayerAddrBlocks[numOtherPlayers].aNode = theEntityAddress.aNode;
  939.                                 otherPlayerAddrBlocks[numOtherPlayers].aSocket = theEntityAddress.aSocket;
  940.                                 
  941.                                 PtoCstr((unsigned char *) &theEntityName);
  942.                                 mystrncpy((char *) &(otherPlayerNames[numOtherPlayers]),(char *) &theEntityName,sizeof(Str32));
  943.                                 
  944.                                 mystrncpy((char *) &(otherPlayerStatus[numOtherPlayers]),"UNKNOWN",sizeof(Str32));
  945.                                 
  946.                                 otherPlayerResponseCount[numOtherPlayers] = 0;
  947.                                 
  948.                                 
  949.                                 //    ping the other player and ask him what he's doing right now
  950.                                 
  951.                                 strcpy((char *) &atpMessage,"SEND STATUS");
  952.                                 
  953.                                 
  954.                                 numBDSBuffers = BuildBDS(otherPlayerRespBuffPtrs[numOtherPlayers],otherPlayerBDSPtrs[numOtherPlayers],sizeof(Str32));
  955.                                 
  956.                                 
  957.                                 (*((ATPParamBlock *) otherPlayerATPPBPtrs[numOtherPlayers])).ATP.ioCompletion = nil;
  958.                                 (*((ATPParamBlock *) otherPlayerATPPBPtrs[numOtherPlayers])).ATP.atpFlags = atpXOvalue;
  959.                                 (*((ATPParamBlock *) otherPlayerATPPBPtrs[numOtherPlayers])).ATP.addrBlock.aNet = otherPlayerAddrBlocks[numOtherPlayers].aNet;
  960.                                 (*((ATPParamBlock *) otherPlayerATPPBPtrs[numOtherPlayers])).ATP.addrBlock.aNode = otherPlayerAddrBlocks[numOtherPlayers].aNode;
  961.                                 (*((ATPParamBlock *) otherPlayerATPPBPtrs[numOtherPlayers])).ATP.addrBlock.aSocket = otherPlayerAddrBlocks[numOtherPlayers].aSocket;
  962.                                 (*((ATPParamBlock *) otherPlayerATPPBPtrs[numOtherPlayers])).ATP.reqLength = sizeof(Str32);
  963.                                 (*((ATPParamBlock *) otherPlayerATPPBPtrs[numOtherPlayers])).ATP.reqPointer = (Ptr) &atpMessage;
  964.                                 (*((ATPParamBlock *) otherPlayerATPPBPtrs[numOtherPlayers])).OTH1.u.numOfBuffs = numBDSBuffers;
  965.                                 (*((ATPParamBlock *) otherPlayerATPPBPtrs[numOtherPlayers])).ATP.bdsPointer = otherPlayerBDSPtrs[numOtherPlayers];
  966.                                 (*((ATPParamBlock *) otherPlayerATPPBPtrs[numOtherPlayers])).SREQ.timeOutVal = 3;
  967.                                 (*((ATPParamBlock *) otherPlayerATPPBPtrs[numOtherPlayers])).SREQ.retryCount = 3;
  968.                                 
  969.                                 errCode = PSendRequest((ATPParamBlock *) otherPlayerATPPBPtrs[numOtherPlayers],true);
  970.                                 
  971.                                 if (errCode != noErr)
  972.                                 {
  973.                                     sprintf(errorMessage,"appleTalkingConnectToOpponents: PSendRequest() error %d, can't get status of newly-found player '%s'",(int) errCode,(char *) &(otherPlayerNames[numOtherPlayers]));
  974.                                     
  975.                                     ErrorAlert(errorMessage);
  976.                                     
  977.                                     errCode = noErr;
  978.                                 }
  979.                                 
  980.                                 else
  981.                                 {
  982.                                     if (numOtherPlayers == 0)
  983.                                     {
  984.                                         GetDItem(theDPtr, 1, &type, &theItem, &tempRect);
  985.                                         HiliteControl((ControlHandle) theItem,0);
  986.                                     }
  987.                                     
  988.                                     numOtherPlayers++;
  989.                                 }
  990.                                 
  991.                                 
  992.                                 //    update the names displayed
  993.                                 
  994.                                 for (i=0;i < NUMSTATICTEXTITEMS;i++)
  995.                                 {
  996.                                     if (i < numOtherPlayers)
  997.                                     {
  998.                                         sprintf(tempString,"%s — %s:%d",(char *) &(otherPlayerNames[i]),(char *) &(otherPlayerStatus[i]),(int) otherPlayerResponseCount[i]);
  999.                                         
  1000.                                         GetDItem(theDPtr, 4+i, &type, &theItem, &tempRect);
  1001.                                         CtoPstr(tempString);
  1002.                                         SetIText(theItem,(unsigned char *) &tempString);
  1003.                                     }
  1004.                                     
  1005.                                     else
  1006.                                     {
  1007.                                         GetDItem(theDPtr, 4+i, &type, &theItem, &tempRect);
  1008.                                         SetIText(theItem,"\p");
  1009.                                     }
  1010.                                 }
  1011.                             }
  1012.                         }
  1013.                     }
  1014.                 }
  1015.             }
  1016.             
  1017.             
  1018.             //    do another NBP lookup
  1019.             
  1020.             NBPSetEntity((Ptr) &theEntityName,"\p=",NBPNETTYPE,"\p*");
  1021.             
  1022.             myMPPPB.NBP.ioCompletion = nil;
  1023.             myMPPPB.NBP.interval = 0x0F;
  1024.             myMPPPB.NBP.count = 0x01;
  1025.             myMPPPB.NBP.nbpPtrs.entityPtr = (Ptr) &theEntityName;
  1026.             myMPPPB.NBP.parm.Lookup.retBuffPtr = nbpNamesBuffer;
  1027.             myMPPPB.NBP.parm.Lookup.retBuffSize = MAXNUMNBPNAMES * NBPNAMESIZE;
  1028.             myMPPPB.NBP.parm.Lookup.maxToGet = MAXNUMNBPNAMES;
  1029.             
  1030.             
  1031.             errCode = PLookupName(&myMPPPB,true);
  1032.             
  1033.             if (errCode != noErr)
  1034.             {
  1035.                 sprintf(errorMessage,"appleTalkingConnectToOpponents: PLookupName() error %d at secondary initial call, can't look up enemy player's NBP names!",(int) errCode);
  1036.                 
  1037.                 goto EXITPOINT;
  1038.             }
  1039.             
  1040.             numNBPScans++;
  1041.             
  1042.             GetDItem(theDPtr, 3, &type, &theItem, &tempRect);
  1043.             sprintf(tempString,"Searching the network for opponents.... (attempt #%d)",(int) numNBPScans);
  1044.             CtoPstr(tempString);
  1045.             SetIText(theItem,(unsigned char *) tempString);
  1046.         }
  1047.         
  1048.         
  1049.         //    check our asynch pings of other players
  1050.         
  1051.         for (i=0;i<numOtherPlayers;i++)
  1052.         {
  1053.             //    did the request complete?
  1054.             
  1055.             if ((*((ATPParamBlock *) otherPlayerATPPBPtrs[i])).ATP.ioResult != 1)
  1056.             {
  1057.                 //    was there an error?
  1058.                 
  1059.                 if ((*((ATPParamBlock *) otherPlayerATPPBPtrs[i])).ATP.ioResult == noErr)
  1060.                 {
  1061.                     //    keep count of how many pings of this player have been done
  1062.                     
  1063.                     otherPlayerResponseCount[i]++;
  1064.                     
  1065.                     //    show the user the other players response
  1066.                     
  1067.                     mystrncpy((char *) &(otherPlayerStatus[i]),(char *) otherPlayerRespBuffPtrs[i],sizeof(Str32));
  1068.                     
  1069.                     if (i < NUMSTATICTEXTITEMS)
  1070.                     {
  1071.                         sprintf(tempString,"%s — %s:%d",(char *) &(otherPlayerNames[i]),(char *) &(otherPlayerStatus[i]),(int) otherPlayerResponseCount[i]);
  1072.                         
  1073.                         GetDItem(theDPtr, 4+i, &type, &theItem, &tempRect);
  1074.                         CtoPstr(tempString);
  1075.                         SetIText(theItem,(unsigned char *) &tempString);
  1076.                     }
  1077.                 }
  1078.                 
  1079.                 else
  1080.                 {
  1081.                     //    an error occurred, so assume that player is gone
  1082.                     
  1083.                     //    kill any requests for the last player, since we're going to move things around
  1084.                     
  1085.                     if ((*((ATPParamBlock *) otherPlayerATPPBPtrs[numOtherPlayers-1])).ATP.ioResult == 1)
  1086.                     {
  1087.                         myCancelATPPB.KILL.aKillQEl = (Ptr) otherPlayerATPPBPtrs[numOtherPlayers-1];
  1088.                         
  1089.                         errCode = PKillSendReq(&myCancelATPPB,false);
  1090.                         
  1091.                         if (errCode != noErr)
  1092.                         {
  1093.                             errCode = noErr;
  1094.                         }
  1095.                     }
  1096.                     
  1097.                     //    have the last player take the place of the current player
  1098.                     
  1099.                     otherPlayerAddrBlocks[i].aNet = otherPlayerAddrBlocks[numOtherPlayers-1].aNet;
  1100.                     otherPlayerAddrBlocks[i].aNode = otherPlayerAddrBlocks[numOtherPlayers-1].aNode;
  1101.                     otherPlayerAddrBlocks[i].aSocket = otherPlayerAddrBlocks[numOtherPlayers-1].aSocket;
  1102.                     
  1103.                     otherPlayerResponseCount[i] = otherPlayerResponseCount[numOtherPlayers-1];
  1104.                     
  1105.                     mystrncpy((char *) &(otherPlayerNames[i]),(char *) &(otherPlayerNames[numOtherPlayers-1]),sizeof(Str32));
  1106.                             
  1107.                     mystrncpy((char *) &(otherPlayerStatus[i]),(char *) &(otherPlayerStatus[numOtherPlayers-1]),sizeof(Str32));
  1108.                     
  1109.                     
  1110.                     //    one less other player that we know about
  1111.                     
  1112.                     numOtherPlayers--;
  1113.                     
  1114.                     if (numOtherPlayers == 0)
  1115.                     {
  1116.                         GetDItem(theDPtr, 1, &type, &theItem, &tempRect);
  1117.                         HiliteControl((ControlHandle) theItem,255);
  1118.                     }
  1119.                     
  1120.                     //    update the screen
  1121.                     
  1122.                     for (j=0;j < NUMSTATICTEXTITEMS;j++)
  1123.                     {
  1124.                         if (j < numOtherPlayers)
  1125.                         {
  1126.                             sprintf(tempString,"%s — %s:%d",(char *) &(otherPlayerNames[j]),(char *) &(otherPlayerStatus[j]),(int) otherPlayerResponseCount[j]);
  1127.                             
  1128.                             GetDItem(theDPtr, 4+j, &type, &theItem, &tempRect);
  1129.                             CtoPstr(tempString);
  1130.                             SetIText(theItem,(unsigned char *) &tempString);
  1131.                         }
  1132.                         
  1133.                         else
  1134.                         {
  1135.                             GetDItem(theDPtr, 4+j, &type, &theItem, &tempRect);
  1136.                             SetIText(theItem,"\p");
  1137.                         }
  1138.                     }
  1139.                 }
  1140.                 
  1141.                 
  1142.                 //    send another ping to the player
  1143.                 
  1144.                 strcpy((char *) &atpMessage,"SEND STATUS");
  1145.                 
  1146.                 
  1147.                 numBDSBuffers = BuildBDS(otherPlayerRespBuffPtrs[i],otherPlayerBDSPtrs[i],sizeof(Str32));
  1148.                 
  1149.                 
  1150.                 (*((ATPParamBlock *) otherPlayerATPPBPtrs[i])).ATP.ioCompletion = nil;
  1151.                 (*((ATPParamBlock *) otherPlayerATPPBPtrs[i])).ATP.atpFlags = atpXOvalue;
  1152.                 (*((ATPParamBlock *) otherPlayerATPPBPtrs[i])).ATP.addrBlock.aNet = otherPlayerAddrBlocks[i].aNet;
  1153.                 (*((ATPParamBlock *) otherPlayerATPPBPtrs[i])).ATP.addrBlock.aNode = otherPlayerAddrBlocks[i].aNode;
  1154.                 (*((ATPParamBlock *) otherPlayerATPPBPtrs[i])).ATP.addrBlock.aSocket = otherPlayerAddrBlocks[i].aSocket;
  1155.                 (*((ATPParamBlock *) otherPlayerATPPBPtrs[i])).ATP.reqLength = sizeof(Str32);
  1156.                 (*((ATPParamBlock *) otherPlayerATPPBPtrs[i])).ATP.reqPointer = (Ptr) &atpMessage;
  1157.                 (*((ATPParamBlock *) otherPlayerATPPBPtrs[i])).OTH1.u.numOfBuffs = numBDSBuffers;
  1158.                 (*((ATPParamBlock *) otherPlayerATPPBPtrs[i])).ATP.bdsPointer = otherPlayerBDSPtrs[i];
  1159.                 (*((ATPParamBlock *) otherPlayerATPPBPtrs[i])).SREQ.timeOutVal = 3;
  1160.                 (*((ATPParamBlock *) otherPlayerATPPBPtrs[i])).SREQ.retryCount = 3;
  1161.                 
  1162.                 errCode = PSendRequest((ATPParamBlock *) otherPlayerATPPBPtrs[i],true);
  1163.                 
  1164.                 if (errCode != noErr)
  1165.                 {
  1166.                     sprintf(errorMessage,"appleTalkingConnectToOpponents: PSendRequest() error %d, can't confirm status of known player '%s'",(int) errCode,(char *) &(otherPlayerNames[i]));
  1167.                     
  1168.                     ErrorAlert(errorMessage);
  1169.                     
  1170.                     errCode = noErr;
  1171.                 }
  1172.             }
  1173.         }
  1174.         
  1175.     } while (itemHit != 1 && itemHit != 2);
  1176.     
  1177.     
  1178.     //    hey-- user pressed Okay!
  1179.     if (itemHit == 1)
  1180.     {
  1181.         appletalkingStatus = PLAYING;
  1182.     }
  1183.     
  1184.     
  1185. EXITPOINT:
  1186.  
  1187.     //    kill off all outstanding NBP and ATP requests
  1188.     
  1189.     if (myMPPPB.NBP.ioResult == 1)
  1190.     {
  1191.         myCancelMPPPB.NBPKILL.nKillQEl = (Ptr) &myMPPPB;
  1192.         
  1193.         errCode = PKillNBP(&myCancelMPPPB,false);
  1194.         
  1195.         if (errCode != noErr && errCode != cbNotFound)
  1196.         {
  1197.             sprintf(errorMessage,"appleTalkingConnectToOpponents: PKillNBP() error %d, can't cancel NBP lookup!",(int) errCode);
  1198.             
  1199.             ErrorAlert(errorMessage);
  1200.             
  1201.             errCode = noErr;
  1202.         }
  1203.         
  1204.         else if (myMPPPB.NBP.ioResult != noErr && myMPPPB.NBP.ioResult != reqAborted)
  1205.         {
  1206.             sprintf(errorMessage,"appleTalkingConnectToOpponents: after PKillNBP(), ioResult for NBP lookup is %d",(int) (myMPPPB.NBP.ioResult));
  1207.             
  1208.             ErrorAlert(errorMessage);
  1209.             
  1210.             errCode = noErr;
  1211.         }
  1212.     }
  1213.     
  1214.     
  1215.     for (i=0;i<MAXNUMPLAYERS;i++)
  1216.     {
  1217.         if (otherPlayerATPPBPtrs[i] != nil)
  1218.         {
  1219.             if ((*((ATPParamBlock *) otherPlayerATPPBPtrs[i])).ATP.ioResult == 1)
  1220.             {
  1221.                 myCancelATPPB.KILL.aKillQEl = (Ptr) otherPlayerATPPBPtrs[i];
  1222.                 
  1223.                 errCode = PKillSendReq(&myCancelATPPB,false);
  1224.                 
  1225.                 if (errCode != noErr && errCode != cbNotFound)
  1226.                 {
  1227.                     sprintf(errorMessage,"appleTalkingConnectToOpponents: PKillSendReq() error %d, can't cancel ATP SendRequest to player #%d!, '%s'",(int) errCode,(int) i,(char *) &(otherPlayerNames[i]));
  1228.                     
  1229.                     ErrorAlert(errorMessage);
  1230.                     
  1231.                     errCode = noErr;
  1232.                 }
  1233.                 
  1234.                 else if ((*((ATPParamBlock *) otherPlayerATPPBPtrs[i])).ATP.ioResult != noErr && (*((ATPParamBlock *) otherPlayerATPPBPtrs[i])).ATP.ioResult != reqAborted)
  1235.                 {
  1236.                     sprintf(errorMessage,"appleTalkingConnectToOpponents: after PKillSendReq(), ioResult for SendRequest #%d is %d",(int) i,(int) ((*((ATPParamBlock *) otherPlayerATPPBPtrs[i])).ATP.ioResult));
  1237.                     
  1238.                     ErrorAlert(errorMessage);
  1239.                     
  1240.                     errCode = noErr;
  1241.                 }
  1242.             }
  1243.             
  1244.             DisposePtr(otherPlayerATPPBPtrs[i]);
  1245.             otherPlayerATPPBPtrs[i] = nil;
  1246.         }
  1247.         
  1248.         if (otherPlayerBDSPtrs[i] != nil)
  1249.         {
  1250.             DisposePtr(otherPlayerBDSPtrs[i]);
  1251.             otherPlayerBDSPtrs[i] = nil;
  1252.         }
  1253.         
  1254.         if (otherPlayerRespBuffPtrs[i] != nil)
  1255.         {
  1256.             DisposePtr(otherPlayerRespBuffPtrs[i]);
  1257.             otherPlayerRespBuffPtrs[i] = nil;
  1258.         }
  1259.     }
  1260.     
  1261.     
  1262.     //    dispose of storage 
  1263.     
  1264.     if (nbpNamesBuffer != nil)
  1265.     {
  1266.         DisposePtr(nbpNamesBuffer);
  1267.         
  1268.         nbpNamesBuffer = nil;
  1269.     }
  1270.     
  1271.     if (theDPtr != nil)
  1272.     {
  1273.         DisposDialog(theDPtr);
  1274.         
  1275.         theDPtr = nil;
  1276.     }
  1277.     
  1278.     if (oldPort != nil)
  1279.     {
  1280.         SetPort(oldPort);
  1281.     }
  1282.     
  1283.     return(errCode);
  1284. }
  1285.  
  1286.  
  1287.  
  1288.  
  1289. //    The ATP completion routine handler in C
  1290.  
  1291. static void ATPReceiveCompletionC(unsigned long A5,ATPParamBlock * theRequestATPPB)
  1292. {
  1293. short            numBDSBuffers;
  1294. OSErr            errCode;
  1295.  
  1296.     //    shall we respond?
  1297.     
  1298.     if (doAsynchATP == true)
  1299.     {
  1300.         //    reply with our current status
  1301.         
  1302.         switch (appletalkingStatus)
  1303.         {
  1304.             case INITIALIZING:
  1305.                 strcpy((char *) myATPAsynchReplyBuffer,"INITIALIZING");
  1306.                 break;
  1307.             
  1308.             case WAITING:
  1309.                 strcpy((char *) myATPAsynchReplyBuffer,"WAITING");
  1310.                 break;
  1311.             
  1312.             case PLAYING:
  1313.                 strcpy((char *) myATPAsynchReplyBuffer,"PLAYING");
  1314.                 break;
  1315.             
  1316.             case CLOSING:
  1317.                 strcpy((char *) myATPAsynchReplyBuffer,"CLOSING");
  1318.                 break;
  1319.             
  1320.             default:
  1321.                 strcpy((char *) myATPAsynchReplyBuffer,"UNKNOWN");
  1322.                 break;
  1323.         }
  1324.         
  1325.         //    set up and then reply to the ping we received
  1326.         
  1327.         asynchATPReplyAddrBlock.aNet = myAsynchReceiveATPPB.theATPParamBlock.ATP.addrBlock.aNet;
  1328.         asynchATPReplyAddrBlock.aNode = myAsynchReceiveATPPB.theATPParamBlock.ATP.addrBlock.aNode;
  1329.         asynchATPReplyAddrBlock.aSocket = myAsynchReceiveATPPB.theATPParamBlock.ATP.addrBlock.aSocket;
  1330.     
  1331.         asynchATPReplyTransID = myAsynchReceiveATPPB.theATPParamBlock.OTH2.transID;
  1332.     
  1333.         
  1334.     
  1335.         numBDSBuffers = BuildBDS(myATPAsynchReplyBuffer,(Ptr) &asynchATPReplyBDS,strlen((char *) myATPAsynchReplyBuffer) + 1);
  1336.         
  1337.         
  1338.         myAsynchReplyATPPB.A5 = A5;
  1339.         
  1340.         myAsynchReplyATPPB.theATPParamBlock.ATP.ioCompletion = (ATPCompletionUPP) ATPReplyCompletionRoutineASM;
  1341.         myAsynchReplyATPPB.theATPParamBlock.ATP.atpSocket = myATPSocketNum;
  1342.         myAsynchReplyATPPB.theATPParamBlock.ATP.atpFlags = atpEOMvalue;
  1343.         myAsynchReplyATPPB.theATPParamBlock.ATP.addrBlock.aNet = myAsynchReceiveATPPB.theATPParamBlock.ATP.addrBlock.aNet;
  1344.         myAsynchReplyATPPB.theATPParamBlock.ATP.addrBlock.aNode = myAsynchReceiveATPPB.theATPParamBlock.ATP.addrBlock.aNode;
  1345.         myAsynchReplyATPPB.theATPParamBlock.ATP.addrBlock.aSocket = myAsynchReceiveATPPB.theATPParamBlock.ATP.addrBlock.aSocket;
  1346.         myAsynchReplyATPPB.theATPParamBlock.ATP.bdsPointer = (Ptr) &asynchATPReplyBDS;
  1347.         myAsynchReplyATPPB.theATPParamBlock.OTH1.u.numOfBuffs = 1;
  1348.         myAsynchReplyATPPB.theATPParamBlock.OTH2.bdsSize = numBDSBuffers;
  1349.         myAsynchReplyATPPB.theATPParamBlock.OTH2.transID = myAsynchReceiveATPPB.theATPParamBlock.OTH2.transID;
  1350.     
  1351.     
  1352.         //    send the response!
  1353.         
  1354.         errCode = PSendResponse(&(myAsynchReplyATPPB.theATPParamBlock),true);
  1355.         
  1356.         if (errCode != noErr)
  1357.         {
  1358.             errCode = noErr;
  1359.         }
  1360.     }
  1361. }
  1362.  
  1363.  
  1364.  
  1365. //    The assembly language glue routine that gets called when an asynch ATP GetRequest completes
  1366.  
  1367. static asm void ATPReceiveCompletionRoutineASM(void)
  1368. {
  1369.     movem.l        D3-D7/A2-A6,-(A7)    //    save registers
  1370.     
  1371.     movea.l        -4(A0),A5    // get A5 from in front of the ATP paramblock, since we put it there before
  1372.     
  1373.     movem.l        A0,-(A7)    //    push a pointer to the paramblock so ATPReceiveCompletionC() can access the paramblock
  1374.     
  1375.     movem.l        A5,-(A7)    //    push A5 so ATPReceiveCompletionC() can use it too
  1376.  
  1377.     jsr            ATPReceiveCompletionC    // call ATPReceiveCompletionC()
  1378.     
  1379.     addq.l        #0x08,A7    //    clean up the stack
  1380.     
  1381.     movem.l        (A7)+,D3-D7/A2-A6    //    restore registers
  1382.     
  1383.     rts        //    that's all....
  1384. }
  1385.  
  1386.  
  1387.  
  1388.  
  1389.  
  1390. //    The C version of the ATP reply routine
  1391.  
  1392. //    Technically, we don't need to do things like this-- we could reuse the GetRequest paramblock when it
  1393. //    completes and then use it to post the reply, but I did it like this anyway....
  1394.  
  1395. static void ATPReplyCompletionC(unsigned long A5,ATPParamBlock * theReplyATPPB)
  1396. {
  1397. OSErr            errCode;
  1398.  
  1399.     //    keep doing this stuff?
  1400.     
  1401.     if (doAsynchATP == true)
  1402.     {
  1403.         myAsynchReceiveATPPB.A5 = A5;
  1404.         
  1405.         myAsynchReceiveATPPB.theATPParamBlock.ATP.ioCompletion = (ATPCompletionUPP) ATPReceiveCompletionRoutineASM;
  1406.         myAsynchReceiveATPPB.theATPParamBlock.ATP.atpSocket = myATPSocketNum;
  1407.         myAsynchReceiveATPPB.theATPParamBlock.ATP.reqLength = MAXATPPACKETSIZE;
  1408.         myAsynchReceiveATPPB.theATPParamBlock.ATP.reqPointer = myATPAsynchReceiveBuffer;
  1409.         
  1410.         errCode = PGetRequest(&(myAsynchReceiveATPPB.theATPParamBlock),true);
  1411.         
  1412.         if (errCode != noErr)
  1413.         {
  1414.             errCode = noErr;
  1415.         }
  1416.     }
  1417. }
  1418.  
  1419.  
  1420. static asm void ATPReplyCompletionRoutineASM(void)
  1421. {
  1422.     movem.l        D3-D7/A2-A6,-(A7)
  1423.     
  1424.     movea.l        -4(A0),A5
  1425.     
  1426.     movem.l        A0,-(A7)
  1427.     
  1428.     movem.l        A5,-(A7)
  1429.  
  1430.     jsr            ATPReplyCompletionC
  1431.     
  1432.     addq.l        #0x08,A7
  1433.     
  1434.     movem.l        (A7)+,D3-D7/A2-A6
  1435.     
  1436.     rts    
  1437. }
  1438.  
  1439.  
  1440.  
  1441.  
  1442.  
  1443. void processDDPPacket(void)
  1444. {
  1445.     if (myDDPReadBuffer.ddpHeaderType == 1 && myDDPReadBuffer.srcSocketNumber == MYGAMEDDPSOCKETNUMBER && myDDPReadBuffer.destNodeID == DDPBROADCASTNODE && myDDPReadBuffer.srcNodeID != myNodeNum)
  1446.     {
  1447.         gameReceiveBroadcastData((Ptr) &myDDPReadBuffer,(long) sizeof(DDPDataPacket));
  1448.     }
  1449. }
  1450.  
  1451.  
  1452.  
  1453.  
  1454. static asm void myDDPSocketListenerASMCode(void)
  1455. {
  1456.         rts
  1457.     
  1458. myA5:    dc.l    0
  1459.  
  1460. ENTRY    static    initMyDDPSocketListener
  1461.         
  1462.         movem.l        A3,-(A7)
  1463.         
  1464.         lea            myA5,A3
  1465.         movem.l        A5,(A3)
  1466.         
  1467.         movem.l        (A7)+,A3
  1468.         
  1469.         rts
  1470.         
  1471. ENTRY    static    myDDPSocketListener
  1472.  
  1473.         lea            myA5,A3
  1474.         movem.l        (A3),A5
  1475.  
  1476.         lea            myDDPReadBuffer.packetData,A3
  1477.         move.l        D1,D3
  1478.         jsr            2(A4)
  1479.         bne            @EXIT
  1480.  
  1481.         
  1482.         movem.l        D4-D7/A5-A6,-(A7)
  1483.         
  1484.         lea            myA5,A3
  1485.         movem.l        (A3),A5
  1486.         
  1487.         lea            myDDPReadBuffer,A3
  1488.         
  1489.         move.b        struct (DDPDataPacket.destNodeID) + toRHA (A2),D2
  1490.         move.b        D2,struct (DDPDataPacket.destNodeID) (A3)
  1491.         
  1492.         move.b        struct (DDPDataPacket.srcNodeID) + toRHA (A2),D2
  1493.         move.b        D2,struct (DDPDataPacket.srcNodeID) (A3)
  1494.         
  1495.         move.b        struct (DDPDataPacket.ddpHeaderType) + toRHA (A2),D2
  1496.         move.b        D2,struct (DDPDataPacket.ddpHeaderType) (A3)
  1497.         
  1498.         move.b        struct (DDPDataPacket.datagramLengthMSB) + toRHA (A2),D2
  1499.         move.b        D2,struct (DDPDataPacket.datagramLengthMSB) (A3)
  1500.         
  1501.         move.b        struct (DDPDataPacket.datagramLengthLSB) + toRHA (A2),D2
  1502.         move.b        D2,struct (DDPDataPacket.datagramLengthLSB) (A3)
  1503.         
  1504.         move.b        struct (DDPDataPacket.destSocketNumber) + toRHA (A2),D2
  1505.         move.b        D2,struct (DDPDataPacket.destSocketNumber) (A3)
  1506.         
  1507.         move.b        struct (DDPDataPacket.srcSocketNumber) + toRHA (A2),D2
  1508.         move.b        D2,struct (DDPDataPacket.srcSocketNumber) (A3)
  1509.         
  1510.         move.b        struct (DDPDataPacket.ddpProtocolType) + toRHA (A2),D2
  1511.         move.b        D2,struct (DDPDataPacket.ddpProtocolType) (A3)
  1512.         
  1513.         
  1514.         jsr            processDDPPacket
  1515.         
  1516.         movem.l        (A7)+,D4-D7/A5-A6
  1517.  
  1518. @EXIT:    rts
  1519. }
  1520.  
  1521.  
  1522.  
  1523. static asm void DDPCompletionRoutineASM(void);
  1524. static void SendDDPCompletionRoutine(void);
  1525. static void InitSendDDPCompletionRoutine(void);
  1526.  
  1527.  
  1528. static asm void DDPCompletionRoutineASM(void)
  1529. {
  1530.         rts
  1531.     
  1532. myA5:    dc.l    0
  1533.  
  1534. ENTRY    static    InitSendDDPCompletionRoutine
  1535.         
  1536.         movem.l        A3,-(A7)
  1537.         
  1538.         lea            myA5,A3
  1539.         movem.l        A5,(A3)
  1540.         
  1541.         movem.l        (A7)+,A3
  1542.         
  1543.         rts
  1544.         
  1545. ENTRY    static    SendDDPCompletionRoutine
  1546.  
  1547.         movem.l        D3-D7/A2-A6,-(A7)
  1548.     
  1549.         lea            myA5,A3
  1550.         movem.l        (A3),A5
  1551.         
  1552.         jsr            gameplayHandleBroadcastCompletion
  1553.         
  1554.         movem.l        (A7)+,D3-D7/A2-A6
  1555.         
  1556.         rts    
  1557. }
  1558.  
  1559.  
  1560.  
  1561.  
  1562. void appleTalkingSendData(Ptr theDataPtr,long theDataLength)
  1563. {
  1564. OSErr                    errCode;
  1565.  
  1566.     if (hasAppleTalk == false)
  1567.     {
  1568.         return;
  1569.     }
  1570.     
  1571.     
  1572.     
  1573.     if (ddpWriteFirstTime == true)
  1574.     {
  1575.         theDDPWriteMPPPB.DDP.ioResult = 0;
  1576.         
  1577.         InitSendDDPCompletionRoutine();
  1578.         
  1579.         ddpWriteFirstTime = false;
  1580.     }
  1581.     
  1582.     
  1583.     if (theDDPWriteMPPPB.DDP.ioResult != 1)
  1584.     {
  1585.         errCode = theDDPWriteMPPPB.DDP.ioResult;
  1586.         
  1587.         if (errCode != noErr)
  1588.         {
  1589.             sprintf(errorMessage,"appleTalkingSendData: PWriteDDP() error %d, asynch send of DDP data packet was unsuccessful!",(int) errCode);
  1590.             
  1591.             ErrorAlert(errorMessage);
  1592.         }
  1593.         
  1594.         if (theDataLength > MAXDDPPACKETSIZE)
  1595.         {
  1596.             theDataLength = MAXDDPPACKETSIZE;
  1597.         }
  1598.         
  1599.         BlockMove(theDataPtr,&(myDDPWriteBuffer.packetData),theDataLength);
  1600.         
  1601.         
  1602.         myDDPBroadcastAddress.aNet = myNetNum;
  1603.         myDDPBroadcastAddress.aNode = DDPBROADCASTNODE;
  1604.         myDDPBroadcastAddress.aSocket = MYGAMEDDPSOCKETNUMBER;
  1605.         
  1606.         BuildDDPwds(myDDPwds,myDDPheader,(Ptr) &(myDDPWriteBuffer.packetData),myDDPBroadcastAddress,(short) MYDDPPACKETTYPE,theDataLength);
  1607.         
  1608.         
  1609.         theDDPWriteMPPPB.DDP.ioCompletion = (MPPCompletionUPP) SendDDPCompletionRoutine;
  1610.         theDDPWriteMPPPB.DDP.socket = myDDPSocketNum;
  1611.         theDDPWriteMPPPB.DDP.checksumFlag = 0;
  1612.         theDDPWriteMPPPB.DDP.u.wdsPointer = (Ptr) &myDDPwds;
  1613.         
  1614. //        errCode = PWriteDDP(&theDDPWriteMPPPB,true);
  1615.         
  1616.         if (errCode != noErr)
  1617.         {
  1618.             sprintf(errorMessage,"appleTalkingSendData: PWriteDDP() error %d, can't start asynch send of DDP data packet!",(int) errCode);
  1619.             
  1620.             ErrorAlert(errorMessage);
  1621.         }
  1622.     }
  1623. }
  1624.  
  1625.  
  1626.  
  1627.